<?php

/**
 * EmailCommand class
 *
 * @author Julot <andy.julot@gmail.com>
 * @since Monday, August 15, 2011. 09:36 AM
 */
class EmailCommand extends CConsoleCommand {

	public function getHelp() {
		return <<<EOD
USAGE
    email [test]
DESCRIPTION
    This command will retrieve email and add it to news.
EOD;
	}

	public function run($args) {
		$params = Yii::app()->params['email'];
		$username = $params['username'];
		echo "Retrieving new email from $username started.\n";
		if ($args && $args[0] == 'test') {
			$this->_test();
		} else {
			$this->_retrieve();
		}
	}

	protected function _splitFrom($value = '') {
		$values = explode('<', $value);
		$froms = array();
		if (count($values) == 1 || trim($values[0]) == '') {
			$value = str_replace(array('<', '>'), array('', ''), $value);
			$values = explode('@', $value);
			$froms['name'] = trim($values[0]);
			$froms['contact'] = trim($value);
		} else {
			$froms['name'] = trim($values[0]);
			$froms['contact'] = str_replace('>', '', trim($values[1]));
		}
		return $froms;
	}

	protected function _getInbox() {
		$params = Yii::app()->params['email'];
		$username = $params['username'];
		$password = $params['password'];
		$hostname = $params['hostname'];

		try {
			$inbox = imap_open($hostname, $username, $password);
		} catch (Exception $exc) {
			return false;
		}

		if ($inbox === false) return false;

		$numbers = imap_search($inbox, 'UNSEEN');
		if ($numbers === false) return array();

		rsort($numbers);
		$emails = array();
		foreach ($numbers as $i=>$number) {
			$structure = imap_fetchstructure($inbox, $number);
			$section = '1';
			$encoding = $structure->encoding;
			$message = trim(imap_fetchbody($inbox, $number, $section));
			if ($message == '') {
				// Maybe encoding detection here is not necessary since now we
				// use detection later?
				if (property_exists($structure, 'parts')) {
					$section .= '.1';
					$encoding = $structure->parts[0]->encoding;
				}
				$message = trim(imap_fetchbody($inbox, $number, $section));
				if ($message == '') {
					if (!$encoding) {
						if (array_key_exists(1, $structure->parts)) {
							$encoding = $structure->parts[1]->encoding;
						}
					}
					// If you enter this section, then the email is mess up.
					// Try every combination.
					foreach (array('1', '1.1', '1.2') as $section) {
						$message = imap_fetchbody($inbox, $number, $section);
						if (trim($message)) break;
					}
				}
			}
			if ($message) {
				$emails[$i]['overview'] = imap_fetch_overview($inbox, $number);
				// This encoding detection is for mail sent from google plus.
				if (!$encoding) {
					if (property_exists($structure, 'parts')) {
						$encoding = $structure->parts[0]->encoding;
						if (!$encoding) {
							if (array_key_exists(1, $structure->parts)) {
								$encoding = $structure->parts[1]->encoding;
							}
						}
					}
				}
				if ($encoding == 3) {
					$message = imap_base64($message);
				} elseif ($encoding == 4) {
					$message = imap_qprint($message);
				}
				$emails[$i]['message'] = $message;
			}
		}
		return $emails;
	}

	protected function _test() {
		echo "!!! TEST MODE !!!\n";

		$emails = $this->_getInbox();
		if ($emails === false) {
			echo 'Cannot connect to Gmail: ' . imap_last_error();
			return;
		}

		echo "Found " . count($emails) . " new mail(s).\n\n";
		foreach ($emails as $i=>$email) {
			$froms = $this->_splitFrom($email['overview'][0]->from);
			$n = $i + 1;
			echo "Mail #$n:\n";
			echo $froms['name'] . ' <' . $froms['contact'] . ">\n";
			echo $email['message'] . "\n\n";
		}
	}

	protected function _retrieve() {
		$params = Yii::app()->params['email'];
		$username = $params['username'];
		$message = "Retrieving email from $username started.";
		$category = 'application.commands.EmailCommand';
		Yii::log($message, 'info', $category);
		$emails = $this->_getInbox();
		if ($emails === false) {
			$message = "Error:\n" . imap_last_error();
			Yii::log($message, 'info', $category);
			return;
		}

		echo "Found " . count($emails) . " new mail(s).\n";
		foreach ($emails as $email) {
			$froms = $this->_splitFrom($email['overview'][0]->from);
			if (stripos($froms['contact'], 'plus.google.com')) {
				continue;
			}

			if (stripos($email['message'], '//hide') !== false) {
				$this->_hide($email);
				continue;
			}

			if (stripos($email['message'], '//blacklist') !== false) {
				$this->_blacklist($email);
				continue;
			}

			$this->_save($email);
		}
	}

	protected function _hide($email) {
		$id = $this->_getId($email['message']);
		$model = News::model()->findByPk($id);
		if ($model) {
			if ($model->hide()) $model->sendHideNotification();
		};
	}

	protected function _blacklist($email) {
		$id = $this->_getId($email['message']);
		$model = News::model()->findByPk($id);
		if ($model) {
			if ($model->blacklist()) $model->sendBlacklistNotification();
		}
	}

	protected function _save($email) {
		$model = new EmailNews;
		$froms = $this->_splitFrom($email['overview'][0]->from);
		$model->sender = $froms['name'];
		$model->dateTime = time();
		$model->contact = $froms['contact'];
		
		// Remove everything after "Original Message" text.
		$messages = array();
		foreach (explode("\n", $email['message']) as $value) {
			if (preg_match("/Original Message/i", $value)) break;
			$messages[] = $value;
		}

		$model->value = implode("\n", $messages);
		echo "Saving mail to news... ";
		if ($model->save()) echo "OK ^_^v\n";
		else echo "Error >_<\n";
		echo "Sending mail notification... ";
		if ($model->sendNotification()) echo "OK ^_^v\n";
		else echo "Error >_<\n";
	}

	protected function _getId($value) {
		$id = 0;
		$matches = array();
		preg_match('/\bSIC-ID: #(\d+)\b/', $value, $matches);
		if (count($matches) == 2) {
			$id = $matches[1];
		}
		return $id;
	}

}
